﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "InplaceEditProjectReference.h"
#include "InplaceEditModelViewProjectData.h"
#include "InplaceEditModeBehavior.h"
#include "InplaceEditSharedContent.h"
#include "InplaceEditProjectStyleMaterialMap.h"

// 平台头文件
#include "DbObjectUtils.h"
#include "IElementParentReporter.h"
#include "IElementBasicInformation.h"
#include "IDocument.h"
#include "IModelView.h"
#include "UniIdentity.h"
#include "IGenericElement.h"
#include "IElementStatus.h"
#include "IElementModelShape.h"
#include "IGraphicsElementShape.h"
#include "IGraphicsElementShapeReference.h"
#include "IElementViewSpecificShapeComponent.h"
#include "IGraphicsNodePathCollector.h"
#include "ICategoryLibrary.h"
#include "ICategory.h"
#include "IGraphicsStyleManager.h"
#include "NdbUpgrade.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"


using namespace gcmp;

namespace gcmp
{
    class InplaceEditSpecificShapeComponent : public NdbObjectSchematic, public IElementViewSpecificShapeComponent
    {
        DBOBJECT_DATA_BEGIN_AND_QUICK_CAST_FROM(gcmp, InplaceEditSpecificShapeComponent, gcmp::NdbObjectSchematic, 7DDC0828 - EE10 - 4CB8 - A0C9 - 95A2C03724FC, gminplaceedit, IElementViewSpecificShapeComponent)
            DATA(OwnerPtr<IRenderPriorityOffsetProvider>, RenderPriorityOffsetProvider)
            DATA_TRANSIENT(IElement*, pOwnerElement)
            DATA(OwnerPtr<IGraphicsNodeVisibilityCustomizer>, GraphicsNodeVisibilityCustomizer)
        DBOBJECT_DATA_END

    public:
        InplaceEditSpecificShapeComponent(IElement* pElement)
            :m_pOwnerElement(pElement)
        {}

        virtual bool IsVisibleInModelView(const IModelView* pModelView) const override
        {
            const InplaceEditModelViewProjectData* pViewData = InplaceEditModelViewProjectData::Get(pModelView);
            if (!pViewData) // 如果不在项目视图，则项目底图不可见
            {
                return false;
            }

            return true;
        }

        virtual OwnerPtr<IGraphicsElementShape> CreateViewSpecificElementShape(const IModelView* pModelView) const override
        {
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(m_pOwnerElement, L"宿主对象为空",L"GDMPLab",L"2024-03-30");
            const InplaceEditProjectReference* pProjectReference = InplaceEditProjectReference::Get(m_pOwnerElement->GetDocument(), m_pOwnerElement->GetElementId());
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pProjectReference, L"宿主对象不是InplaceEditProjectReference类型",L"GDMPLab",L"2024-03-30");
            const IGraphicsElementShape* pGrep = pProjectReference->GetModelViewGrep(pModelView);
            if (pGrep)
            {
                return TransferOwnershipCast<IGraphicsElementShape>(pGrep->Clone());
            }
            return nullptr;
        }
        virtual bool IsCuttableByModelViewRange(const IModelView* pModelView) const override
        {
            const InplaceEditModelViewProjectData* pViewData = InplaceEditModelViewProjectData::Get(pModelView);
            if (!pViewData) // 如果不在项目视图，则不需要视图切割
            {
                return false;
            }
            return true;
        }

        virtual void ReportDependentElements(std::vector<ElementId>& dependentElementIds) const override {};

        virtual void SetRenderPriorityOffsetProvider(OwnerPtr<IRenderPriorityOffsetProvider> opProvider) override;
        virtual const IRenderPriorityOffsetProvider* GetRenderPriorityOffsetProvider() const override;
        virtual IRenderPriorityOffsetProvider* GetRenderPriorityOffsetProvider() override;

        virtual void SetGraphicsNodeVisibilityCustomizer(OwnerPtr<IGraphicsNodeVisibilityCustomizer> opCustomizer) override;
        virtual const IGraphicsNodeVisibilityCustomizer* GetGraphicsNodeVisibilityCustomizer() const override;
        virtual IGraphicsNodeVisibilityCustomizer* GetGraphicsNodeVisibilityCustomizer() override;

    public:
        virtual bool SetOwnerElement(IElement* pOwnerElement) override 
        { 
            m_pOwnerElement = pOwnerElement;
            IGraphicsNodeVisibilityCustomizer* pCustomizer = GetGraphicsNodeVisibilityCustomizerFW__().get();
            if (pCustomizer)
            {
                pCustomizer->SetOwnerElement(pOwnerElement);
            }
            return true;
        }
        virtual IElement* GetOwnerElement() override { return m_pOwnerElement; }
        virtual const IElement* GetOwnerElement() const override { return m_pOwnerElement; }

    public: //实现NdbObject接口
        virtual NdbObject* GetTopOwnerObject() const override
        {
            return nullptr;//
        }

    private:
        
    };

    BEGIN_UPGRADE_CLASS(gcmp, InplaceEditSpecificShapeComponent, 2)
        ADD_OWNERPTR_IDB_PROPERTY(OwnerPtr<IRenderPriorityOffsetProvider>, RenderPriorityOffsetProvider)
    END_UPGRADE_CLASS

    BEGIN_UPGRADE_CLASS(gcmp, InplaceEditSpecificShapeComponent, 3)
        ADD_OWNERPTR_IDB_PROPERTY(OwnerPtr<IGraphicsNodeVisibilityCustomizer>, GraphicsNodeVisibilityCustomizer)
    END_UPGRADE_CLASS

    DBOBJECT_DATA_DEFINE(InplaceEditSpecificShapeComponent)
    {
        m_GraphicsNodeVisibilityCustomizer = nullptr;
    }

    void InplaceEditSpecificShapeComponent::SetRenderPriorityOffsetProvider(OwnerPtr<IRenderPriorityOffsetProvider> opProvider)
    {
        SetRenderPriorityOffsetProvider__(TransferOwnership(opProvider));
    }

    const IRenderPriorityOffsetProvider* InplaceEditSpecificShapeComponent::GetRenderPriorityOffsetProvider() const
    {
        return GetRenderPriorityOffsetProvider__().get();
    }

    IRenderPriorityOffsetProvider* InplaceEditSpecificShapeComponent::GetRenderPriorityOffsetProvider()
    {
        return GetRenderPriorityOffsetProviderFW__().get();
    }

    void InplaceEditSpecificShapeComponent::SetGraphicsNodeVisibilityCustomizer(OwnerPtr<IGraphicsNodeVisibilityCustomizer> opCustomizer)
    {
        if (opCustomizer)
        {
            opCustomizer->SetOwnerElement(GetOwnerElement());
        }
        SetGraphicsNodeVisibilityCustomizer__(TransferOwnership(opCustomizer));
    }

    const IGraphicsNodeVisibilityCustomizer* InplaceEditSpecificShapeComponent::GetGraphicsNodeVisibilityCustomizer() const
    {
        return GetGraphicsNodeVisibilityCustomizer__().get();
    }

    IGraphicsNodeVisibilityCustomizer* InplaceEditSpecificShapeComponent::GetGraphicsNodeVisibilityCustomizer()
    {
        return GetGraphicsNodeVisibilityCustomizerFW__().get();
    }

    class StyleMaterialIdTester : public gcmp::IGraphicsNodePathTester
    {
    public:
        virtual bool IsDesiredGraphicsNodePath(const IGraphicsNodePath& nodePath) const override
        {
            return true;
        }
    };

    // 项目底图形体的材质样式Id替换
    class StyleMaterialIdProcessor : public IGraphicsNodeProcessor
    {
    private:
        const InplaceEditProjectStyleMaterialMap* m_StyleMaterialMap;
    public:
        StyleMaterialIdProcessor(const InplaceEditProjectStyleMaterialMap* pStyleMaterialMap)
            : m_StyleMaterialMap(pStyleMaterialMap)
        {}

        virtual void Process(IGraphicsNode* pGraphicsNode) override
        {
            if (pGraphicsNode->GetGraphicsMaterialId().IsValid())
            {
                ElementId familyMaterialId = m_StyleMaterialMap->GetFamilyMaterialId(pGraphicsNode->GetGraphicsMaterialId());
                pGraphicsNode->SetGraphicsMaterialId(familyMaterialId);
            }
            if (pGraphicsNode->GetGraphicsStyleId().IsValid())
            {
                ElementId familyStyleId = m_StyleMaterialMap->GetFamilyStyleId(pGraphicsNode->GetGraphicsStyleId());
                pGraphicsNode->SetGraphicsStyleId(familyStyleId);
            }
        }
    };

    bool ReplaceStyleMaterialId(IDocument *pDoc, IGraphicsElementShape* pGrep)
    {
        const InplaceEditProjectStyleMaterialMap *pStyleMaterialMap = InplaceEditProjectStyleMaterialMap::Get(pDoc);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pStyleMaterialMap, L"项目底图的材质样式映射为空",L"GDMPLab",L"2024-03-30");
        OwnerPtr<IGraphicsNodePathCollector> opCollector = IGraphicsNodePathCollector::Create(pDoc, pGrep);
        OwnerPtr<StyleMaterialIdTester> opTester = NEW_AS_OWNER_PTR(StyleMaterialIdTester);
        OwnerPtr<StyleMaterialIdProcessor> opProcessor = NEW_AS_OWNER_PTR(StyleMaterialIdProcessor, pStyleMaterialMap);
        opCollector->ProcessGraphicsNodes(opTester.get(), opProcessor.get());
        return true;
    }
}


DBOBJECT_DATA_DEFINE(InplaceEditProjectReference)
{
    m_pOwnerElement = nullptr;
}

const InplaceEditProjectReference *InplaceEditProjectReference::Get(IDocument *pDoc, ElementId elementId)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"参数为空",L"GDMPLab",L"2024-03-30");
    const IGenericElement *pGenericElement = quick_cast<IGenericElement>(pDoc->GetElement(elementId));
    if (pGenericElement && pGenericElement->GetExternalObject())
    {
        return quick_cast<const InplaceEditProjectReference>(pGenericElement->GetExternalObject());
    }

    return nullptr;
}

InplaceEditProjectReference *InplaceEditProjectReference::GetFw(IDocument *pDoc, ElementId elementId)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"参数为空",L"GDMPLab",L"2024-03-30");
    IGenericElement *pGenericElement = quick_cast<IGenericElement>(pDoc->GetElement(elementId));
    if (pGenericElement && pGenericElement->GetExternalObject())
    {
        return quick_cast<InplaceEditProjectReference>(pGenericElement->GetExternalObject());
    }

    return nullptr;
}

InplaceEditProjectReference* InplaceEditProjectReference::AddSharedElementInfo(IDocument *pDoc
    , OwnerPtr<InplaceEditSharedElementInfo> opElementInfo, const std::wstring& viewName)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc && opElementInfo, L"参数为空",L"GDMPLab",L"2024-03-30");
    InplaceEditModeBehavior *pInplaceEdit = InplaceEditModeBehavior::GetFw(pDoc);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInplaceEdit, L"不在在位编辑下不能创建项目引用对象",L"GDMPLab",L"2024-03-30");
    OwnerPtr<IGraphicsElementShape> opGrep = opElementInfo->FetchGRep();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opGrep, L"InplaceEditSharedElementInfo不能没有Grep",L"GDMPLab",L"2024-03-30");

    // 根据Grep的ElementId检查旧的对象是否已经存在，如果不存在，则需要创建时间，如果已存在，则直接将视图Grep信息加入旧的对象
    int64_t projectElementId = opGrep->GetElementId().AsInt64();
    ElementId referenceId = pInplaceEdit->GetReferenceElementId(projectElementId);
    InplaceEditProjectReference *pProjectReference = nullptr;
    if (referenceId.IsValid())
    {
        pProjectReference = InplaceEditProjectReference::GetFw(pDoc, referenceId);
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pProjectReference, L"pProjectReference不存在：" + StringUtil::ToWString(referenceId.AsInt64()),L"GDMPLab",L"2024-03-30");
    }
    else
    {
        IGenericElement* pElement = IGenericElement::Create(
            pDoc,
            NEW_AS_OWNER_PTR(InplaceEditProjectReference),
            InplaceEditProjectReference::GetClassId().GetGuid(),
            ElementCreationOptions::Normal
        );
        pProjectReference = quick_cast<InplaceEditProjectReference>(pElement->GetExternalObject());
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pProjectReference, L"InplaceEditProjectReference创建失败",L"GDMPLab",L"2024-03-30");

        if (ICategoryLibrary::Get(pDoc)->GetCategory(opElementInfo->GetCategoryUid()) == nullptr)
        {
            OwnerPtr<ICategory> opCategory = ICategory::Create(opElementInfo->GetCategoryUid(), UniIdentity::InvalidUid, L"InplaceEditProjectReference", L"InplaceEditProjectReference");
            ICategoryLibrary::Get(pDoc)->AddCategory(TransferOwnership(opCategory));
        }

        IGraphicsStyleManager* pGraphicStyleManager = pDoc->GetGraphicsStyleManager();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pGraphicStyleManager, L"GraphicsStyleManager为空",L"GDMPLab",L"2024-03-30");
        if (pGraphicStyleManager->GetGraphicsStyleIdByCategoryUid(opElementInfo->GetCategoryUid()) == ElementId::InvalidID)
        {
            pGraphicStyleManager->CreateGraphicsStyleForCategory(opElementInfo->GetCategoryUid(), *(IGraphicsStyleData::Create()));
        }
        // 设置类别
        pElement->GetBasicInformation()->SetCategoryUid(opElementInfo->GetCategoryUid());

        pElement->SetViewSpecificShapeComponent(NEW_AS_OWNER_PTR(InplaceEditSpecificShapeComponent, pElement));

        pElement->GetStatus()->SetIsModifiable(false);// 禁用构件非罗盘操作的变换

        // 添加到map记录
        pInplaceEdit->AddReferenceElement(pElement->GetElementId(), projectElementId);
    }

    // 替换Grep引用的材质样式Id
    ReplaceStyleMaterialId(pDoc, opGrep.get());
    opGrep->SetElementId(pProjectReference->GetOwnerElementId());

    // 设置视图形体
    pProjectReference->GetViewGrepsFW__()[viewName] = TransferOwnership(opGrep);

    return pProjectReference;
}

bool gcmp::InplaceEditProjectReference::AddSharedViewContent(IDocument *pDoc, InplaceEditSharedViewContent* pViewContent)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc && pViewContent, L"参数为空",L"GDMPLab",L"2024-03-30");

    InplaceEditProjectStyleMaterialMap *pStyleMaterialMap = InplaceEditProjectStyleMaterialMap::GetFw(pDoc);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pStyleMaterialMap, L"项目底图的材质样式映射为空",L"GDMPLab",L"2024-03-30");

    // 族文档需要创建对应的材质样式
    FOR_EACH(opStyleInfo, pViewContent->GetStyleInfos())
    {
        OwnerPtr<IGraphicsStyleData> opStyleData = opStyleInfo->GetAsGraphicsStyleData();
        pStyleMaterialMap->AddProjectStyle(opStyleInfo->GetStyleId(), opStyleData.get());
    }
    FOR_EACH(opMaterialInfo, pViewContent->GetMaterialInfos())
    {
        OwnerPtr<IGraphicsMaterialData> opMaterialData = opMaterialInfo->GetAsGraphicsMaterialData();
        pStyleMaterialMap->AddProjectMaterial(opMaterialInfo->GetMaterialId(), opMaterialData.get());
    }
    //创建填充样式
    FOR_EACH(opFillpatternInfo, pViewContent->GetFillPatternInfos())
    {
        OwnerPtr<IFillPatternData> opFillPatternData = opFillpatternInfo->GetAsFillPatternData();
        pStyleMaterialMap->AddProjectFillPattern(opFillpatternInfo->GetGenericId(), opFillPatternData.get());
    }

    //创建线型
    FOR_EACH(opLineTypeNewInfo, pViewContent->GetLineTypeNewInfos())
    {
        OwnerPtr<ILineTypeData> opLineTypeData = opLineTypeNewInfo->GetAsLineTypeData();
        pStyleMaterialMap->AddProjectLineTypeNew(opLineTypeNewInfo->GetGenericId(), opLineTypeData.get());
    }

    FOR_EACH_INDEX(i, pViewContent->GetSharedElementInfosFW())
    {
        AddSharedElementInfo(pDoc, TransferOwnership(pViewContent->GetSharedElementInfosFW()[i]), pViewContent->GetViewName());
    }
    return true;
}

IDocument *InplaceEditProjectReference::GetDocument() const
{
    if (!m_pOwnerElement)
    {
        return nullptr;
    }
    return m_pOwnerElement->GetDocument();
}

ElementId InplaceEditProjectReference::GetOwnerElementId() const
{
    if (!m_pOwnerElement)
    {
        return ElementId::InvalidID;
    }
    return m_pOwnerElement->GetElementId();
}

const IGraphicsElementShape* gcmp::InplaceEditProjectReference::GetModelViewGrep(const IModelView* pModelView) const
{
    if (!pModelView)
    {
        return nullptr;
    }

    auto iter = GetViewGreps__().find(pModelView->GetName());
    if (iter != GetViewGreps__().end())
    {
        return iter->second.get();
    }

    return nullptr;
}

#pragma region IExternalObject接口
NdbObject* InplaceEditProjectReference::GetTopOwnerObject() const
{
    return quick_cast<NdbObject>(const_cast<IElement*>(GetOwnerElement()));
}

#pragma region 关联更新

void InplaceEditProjectReference::UpdateForWeakParentDeletion(const std::set<ElementId>& deletedElementIds)
{

}

void InplaceEditProjectReference::ReportParents(IElementParentReporter& reporter) const
{
    const IElement* pElement = GetOwnerElement();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElement, L"IElement为空",L"GDMPLab",L"2024-03-30");

    const IElementModelShape *pModelShape = m_pOwnerElement->GetElementModelShape();
    if (pModelShape && pModelShape->GetGraphicsElementShape())
    {
        std::vector<ElementId> refIds;
        pModelShape->GetGraphicsElementShape()->GetReferencedElementIds(refIds);
        reporter.ReportWeak(refIds);
    }
    FOR_EACH(item, GetViewGreps__())
    {
        std::vector<ElementId> refIds;
        item.second->GetReferencedElementIds(refIds);
        reporter.ReportWeak(refIds);
    }
}

#pragma endregion 关联更新

#pragma region 其他
bool InplaceEditProjectReference::FinishEditing()
{
    return true;
}
#pragma endregion 其他

#pragma region protected

bool InplaceEditProjectReference::SetOwnerElement(IElement* pOwnerElement)
{
    m_pOwnerElement = pOwnerElement;
    return true;
}

#pragma endregion protected
#pragma endregion IExternalObject接口
